"""
实验模板服务层
处理实验模板的业务逻辑
"""
import json
from typing import List, Optional, Tuple
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy import desc, asc, or_

from models.experiment_template import ExperimentTemplate
from schemas.template_schema import (
    ExperimentTemplateCreate,
    ExperimentTemplateUpdate,
    VersionInfo
)
from utils.yaml_parser import (
    json_to_yaml,
    yaml_to_json,
    validate_yaml,
    validate_experiment_template
)


class TemplateService:
    """实验模板服务"""

    @staticmethod
    def create_template(
        db: Session,
        template_create: ExperimentTemplateCreate
    ) -> Tuple[bool, str, Optional[ExperimentTemplate]]:
        """
        创建实验模板

        Args:
            db: 数据库会话
            template_create: 创建模板的请求数据

        Returns:
            (是否成功, 错误信息, 模板对象)
        """
        # 验证 YAML 格式
        is_valid, error_msg = validate_yaml(template_create.yaml_content)
        if not is_valid:
            return False, f"YAML 格式错误: {error_msg}", None

        # 解析 YAML 为 JSON
        try:
            json_config = yaml_to_json(template_create.yaml_content)
        except Exception as e:
            return False, f"YAML 解析失败: {str(e)}", None

        # 验证必填字段
        is_valid, error_msg = validate_experiment_template(json_config)
        if not is_valid:
            return False, error_msg, None

        # 检查名称唯一性
        existing = db.query(ExperimentTemplate).filter(
            ExperimentTemplate.name == template_create.name,
            ExperimentTemplate.deleted_at.is_(None)
        ).first()
        if existing:
            return False, f"模板名称 '{template_create.name}' 已存在", None

        # 创建模板
        template = ExperimentTemplate(
            name=template_create.name,
            description=template_create.description,
            yaml_content=template_create.yaml_content,
            json_config=json.dumps(json_config, ensure_ascii=False),
            application_id=template_create.application_id,
            tags=json.dumps(template_create.tags or [], ensure_ascii=False),
            version=1,
            parent_version_id=None,
            change_log="初始版本",
            created_by=template_create.created_by
        )

        db.add(template)
        db.commit()
        db.refresh(template)

        return True, "", template

    @staticmethod
    def get_template_list(
        db: Session,
        page: int = 1,
        page_size: int = 20,
        name: Optional[str] = None,
        tags: Optional[str] = None,
        sort_by: str = "created_at",
        order: str = "desc"
    ) -> Tuple[int, List[ExperimentTemplate]]:
        """
        查询模板列表（每个模板名称只返回最新版本）

        Args:
            db: 数据库会话
            page: 页码
            page_size: 每页数量
            name: 模板名称(模糊查询)
            tags: 标签(逗号分隔)
            sort_by: 排序字段
            order: 排序方向

        Returns:
            (总数, 模板列表)
        """
        from sqlalchemy import func

        # 子查询：获取每个模板名称的最新版本ID
        subquery = db.query(
            ExperimentTemplate.name,
            func.max(ExperimentTemplate.version).label('max_version')
        ).filter(
            ExperimentTemplate.deleted_at.is_(None)
        ).group_by(ExperimentTemplate.name).subquery()

        # 主查询：根据名称和最新版本号关联
        query = db.query(ExperimentTemplate).join(
            subquery,
            (ExperimentTemplate.name == subquery.c.name) &
            (ExperimentTemplate.version == subquery.c.max_version)
        ).filter(
            ExperimentTemplate.deleted_at.is_(None)
        )

        # 名称模糊查询
        if name:
            query = query.filter(ExperimentTemplate.name.like(f"%{name}%"))

        # 标签过滤
        if tags:
            tag_list = [tag.strip() for tag in tags.split(",")]
            # SQLite 不支持 JSON 查询,使用 LIKE 模糊匹配
            tag_filters = [ExperimentTemplate.tags.like(f"%{tag}%") for tag in tag_list]
            query = query.filter(or_(*tag_filters))

        # 总数
        total = query.count()

        # 排序
        sort_column = getattr(ExperimentTemplate, sort_by, ExperimentTemplate.created_at)
        if order == "asc":
            query = query.order_by(asc(sort_column))
        else:
            query = query.order_by(desc(sort_column))

        # 分页
        offset = (page - 1) * page_size
        templates = query.offset(offset).limit(page_size).all()

        return total, templates

    @staticmethod
    def get_template_by_id(db: Session, template_id: int) -> Optional[ExperimentTemplate]:
        """
        根据 ID 查询模板

        Args:
            db: 数据库会话
            template_id: 模板 ID

        Returns:
            模板对象或 None
        """
        return db.query(ExperimentTemplate).filter(
            ExperimentTemplate.id == template_id,
            ExperimentTemplate.deleted_at.is_(None)
        ).first()

    @staticmethod
    def get_version_history(db: Session, template_id: int) -> List[VersionInfo]:
        """
        获取版本历史

        Args:
            db: 数据库会话
            template_id: 模板 ID

        Returns:
            版本信息列表
        """
        # 获取当前模板
        current = db.query(ExperimentTemplate).filter(
            ExperimentTemplate.id == template_id,
            ExperimentTemplate.deleted_at.is_(None)
        ).first()

        if not current:
            return []

        # 获取所有同名模板的历史版本
        versions = db.query(ExperimentTemplate).filter(
            ExperimentTemplate.name == current.name,
            ExperimentTemplate.deleted_at.is_(None)
        ).order_by(desc(ExperimentTemplate.version)).all()

        return [
            VersionInfo(
                version=v.version,
                created_at=v.created_at,
                change_log=v.change_log
            )
            for v in versions
        ]

    @staticmethod
    def get_template_by_name_and_version(
        db: Session,
        name: str,
        version: int
    ) -> Optional[ExperimentTemplate]:
        """
        根据模板名称和版本号查询模板

        Args:
            db: 数据库会话
            name: 模板名称
            version: 版本号

        Returns:
            模板对象或 None
        """
        return db.query(ExperimentTemplate).filter(
            ExperimentTemplate.name == name,
            ExperimentTemplate.version == version,
            ExperimentTemplate.deleted_at.is_(None)
        ).first()

    @staticmethod
    def update_template(
        db: Session,
        template_id: int,
        template_update: ExperimentTemplateUpdate
    ) -> Tuple[bool, str, Optional[ExperimentTemplate]]:
        """
        更新模板(创建新版本)

        Args:
            db: 数据库会话
            template_id: 模板 ID
            template_update: 更新数据

        Returns:
            (是否成功, 错误信息, 新版本模板对象)
        """
        # 获取当前模板
        current_template = TemplateService.get_template_by_id(db, template_id)
        if not current_template:
            return False, "模板不存在", None

        # 准备新版本数据
        new_name = template_update.name if template_update.name is not None else current_template.name
        new_description = template_update.description if template_update.description is not None else current_template.description
        new_yaml = template_update.yaml_content if template_update.yaml_content is not None else current_template.yaml_content
        new_application_id = template_update.application_id if template_update.application_id is not None else current_template.application_id
        new_tags_list = template_update.tags if template_update.tags is not None else json.loads(current_template.tags)

        # 如果修改了名称,检查唯一性
        if new_name != current_template.name:
            existing = db.query(ExperimentTemplate).filter(
                ExperimentTemplate.name == new_name,
                ExperimentTemplate.deleted_at.is_(None)
            ).first()
            if existing:
                return False, f"模板名称 '{new_name}' 已存在", None

        # 验证 YAML 格式
        is_valid, error_msg = validate_yaml(new_yaml)
        if not is_valid:
            return False, f"YAML 格式错误: {error_msg}", None

        # 解析 YAML
        try:
            json_config = yaml_to_json(new_yaml)
        except Exception as e:
            return False, f"YAML 解析失败: {str(e)}", None

        # 验证必填字段
        is_valid, error_msg = validate_experiment_template(json_config)
        if not is_valid:
            return False, error_msg, None

        # 创建新版本
        new_version = ExperimentTemplate(
            name=new_name,
            description=new_description,
            yaml_content=new_yaml,
            json_config=json.dumps(json_config, ensure_ascii=False),
            application_id=new_application_id,
            tags=json.dumps(new_tags_list, ensure_ascii=False),
            version=current_template.version + 1,
            parent_version_id=current_template.id,
            change_log=template_update.change_log or f"更新版本 {current_template.version + 1}",
            created_by=current_template.created_by
        )

        db.add(new_version)
        db.commit()
        db.refresh(new_version)

        return True, "", new_version

    @staticmethod
    def delete_template(db: Session, template_id: int) -> Tuple[bool, str]:
        """
        删除模板(软删除)

        Args:
            db: 数据库会话
            template_id: 模板 ID

        Returns:
            (是否成功, 错误信息)
        """
        template = TemplateService.get_template_by_id(db, template_id)
        if not template:
            return False, "模板不存在"

        # TODO: 检查是否被工作流引用
        # 当前版本暂不实现,直接删除

        # 软删除
        template.deleted_at = datetime.now()
        db.commit()

        return True, ""

    @staticmethod
    def get_version_diff(
        db: Session,
        template_id: int,
        version1: int,
        version2: int
    ) -> Tuple[bool, str, Optional[dict]]:
        """
        获取版本对比

        Args:
            db: 数据库会话
            template_id: 模板 ID
            version1: 版本号1
            version2: 版本号2

        Returns:
            (是否成功, 错误信息, 对比数据)
        """
        # 获取当前模板
        current = TemplateService.get_template_by_id(db, template_id)
        if not current:
            return False, "模板不存在", None

        # 获取两个版本
        v1 = db.query(ExperimentTemplate).filter(
            ExperimentTemplate.name == current.name,
            ExperimentTemplate.version == version1,
            ExperimentTemplate.deleted_at.is_(None)
        ).first()

        v2 = db.query(ExperimentTemplate).filter(
            ExperimentTemplate.name == current.name,
            ExperimentTemplate.version == version2,
            ExperimentTemplate.deleted_at.is_(None)
        ).first()

        if not v1 or not v2:
            return False, "指定的版本不存在", None

        # 简单的 diff 实现
        diff_text = f"=== 版本 {version1} vs 版本 {version2} ===\n\n"
        diff_text += f"--- 版本 {version1} ---\n{v1.yaml_content}\n\n"
        diff_text += f"+++ 版本 {version2} ---\n{v2.yaml_content}\n"

        return True, "", {
            "version1": {
                "version": v1.version,
                "yaml_content": v1.yaml_content,
                "change_log": v1.change_log
            },
            "version2": {
                "version": v2.version,
                "yaml_content": v2.yaml_content,
                "change_log": v2.change_log
            },
            "diff": diff_text
        }

    @staticmethod
    def rollback_to_version(
        db: Session,
        template_id: int,
        target_version: int
    ) -> Tuple[bool, str, Optional[ExperimentTemplate]]:
        """
        回滚到指定版本(创建新版本)

        Args:
            db: 数据库会话
            template_id: 模板 ID
            target_version: 目标版本号

        Returns:
            (是否成功, 错误信息, 新版本模板对象)
        """
        # 获取当前模板
        current = TemplateService.get_template_by_id(db, template_id)
        if not current:
            return False, "模板不存在", None

        # 获取目标版本
        target = db.query(ExperimentTemplate).filter(
            ExperimentTemplate.name == current.name,
            ExperimentTemplate.version == target_version,
            ExperimentTemplate.deleted_at.is_(None)
        ).first()

        if not target:
            return False, f"版本 {target_version} 不存在", None

        # 创建新版本(内容来自目标版本)
        new_version = ExperimentTemplate(
            name=current.name,
            description=target.description,
            yaml_content=target.yaml_content,
            json_config=target.json_config,
            tags=target.tags,
            version=current.version + 1,
            parent_version_id=current.id,
            change_log=f"回滚到版本 {target_version}",
            created_by=current.created_by
        )

        db.add(new_version)
        db.commit()
        db.refresh(new_version)

        return True, "", new_version
